﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Collections;

namespace AntikCompta.Data
{
    public delegate void DataChangedHandler();

    [XmlRoot("Exercice")]
    public class Exercice
    {
        private int mAnnee;
        private List<Produit> mProduitListe;
        private Caisse mCaisse;
        public event DataChangedHandler DataChanged;
        private List<CaisseElement> mFrais;

        public Exercice()
        {
            mProduitListe = new List<Produit>();
            mCaisse = new Caisse();
            mFrais = new List<CaisseElement>();
        }

        public Exercice(int aAnnee)
        {
            mAnnee = aAnnee;
            mProduitListe = new List<Produit>();
            mCaisse = new Caisse();
            mFrais = new List<CaisseElement>();
        }

        public bool AjouterProduit(Produit aProd)
        {
            if (Exists(aProd.Reference) == true)
                return false;

            mProduitListe.Add(aProd);

            SendChange();

            return true;
        }

        private void SendChange()
        {
            if (DataChanged != null)
                DataChanged();
        }

        internal float GetResteCaisse(ref Stock aStock, int aMois)
        {
            float somme = AddVentes(ref aStock, aMois) + AddRecette(aMois);
            somme = somme - AddAchats(aMois) - AddFrais(aMois) - AddDepense(aMois);
            return somme;
        }

        private float AddDepense(int mois)
        {
            float somme = 0;
            foreach (CaisseElement elmt in Caisse.Depences)
            {
                if (elmt.Date.Month <= mois)
                    somme += elmt.Somme;
            }

            return somme;
        }

        private float AddRecette(int mois)
        {
            float somme = 0;
            foreach (CaisseElement elmt in Caisse.Recettes)
            {
                if (elmt.Date.Month <= mois)
                    somme += elmt.Somme;
            }
            return somme;
        }

        private float AddFrais(int aMois)
        {
            float somme = 0;
            foreach (CaisseElement ce in Frais)
            {
                if (ce.Date.Month <= aMois)
                    somme += ce.Somme;
            }

            return somme;
        }

        private float AddVentes(ref Stock aStock, int aMois)
        {
            float somme = 0;
            List<Produit> liste;
            if (aStock.GetVentes(Annee, out liste) == true)
            {
                foreach (Produit p in liste)
                {
                    Especes esp = p.ModePayementVente as Especes;
                    if ((esp != null) && (p.DateVente.Month <= aMois))
                        somme += p.PrixVente;
                }
            }
            return somme;
        }

        private float AddAchats(int aMois)
        {
            float somme = 0;
            foreach (Produit p in ProduitListe)
            {
                Especes esp = p.ModePayementAchat as Especes;
                if ((esp != null) && (p.DateAchat.Month <= aMois) )
                    somme += p.PrixAchat;
            }
            return somme;
        }

        public bool SetProduit(ref Produit aProd)
        {
            Produit prod;
            if (GetProduit(aProd.Reference, out prod) == false)
                return false;

            mProduitListe.Remove(prod);
            mProduitListe.Add(aProd);

            SendChange();

            return true;
        }

        public void AjouterFrais(CaisseElement aElmt)
        {
            mFrais.Add(aElmt);
            SendChange();
        }

        public bool GetFrais(int aRef, out CaisseElement aFrais)
        {
            aFrais = null;
            IEnumerator<CaisseElement> iter = mFrais.GetEnumerator();
            while ((iter.MoveNext()) && (aFrais == null))
            {
                if (iter.Current.Reference == aRef)
                    aFrais = iter.Current;
            }
            return aFrais != null;
        }

        public bool GetProduit(String aReference, out Produit aProd)
        {
            aProd = null;
            IEnumerator<Produit> iter = mProduitListe.GetEnumerator();
            while ((iter.MoveNext()) && (aProd == null))
            {
                if (iter.Current.Reference == aReference)
                    aProd = iter.Current;
            }

            return aProd != null;
        }

        [XmlAttributeAttribute()]
        public int Annee
        {
            get { return mAnnee; }
            set { mAnnee = value; SendChange(); }
        }

        [XmlElement()]
        public Caisse Caisse
        {
            get { return mCaisse; }
            set { mCaisse = value; }
        }

        [XmlElement()]
        public List<CaisseElement> Frais
        {
            get { return mFrais; }
            set { mFrais = value; }
        }

        [XmlArray("Produits"), XmlArrayItem("Produit")]
        public List<Produit> ProduitListe
        {
            get { return mProduitListe; }
            set { mProduitListe = value; SendChange(); }
        }

        internal List<Produit> Achats
        {
            get
            {
                List<Produit> liste = new List<Produit>();
                foreach (Produit p in mProduitListe)
                {
                    if ( p.DateAchat.Year==Annee )
                        liste.Add(p);
                }
                return liste;
            }
        }

        internal List<Produit> Ventes
        {
            get
            {
                List<Produit> liste = new List<Produit>();
                foreach (Produit p in mProduitListe)
                {
                    if (p.DateVente != DateTime.MinValue)
                        liste.Add(p);
                }
                return liste;
            }
        }

        internal bool GetBilan(int aAnnnee, ref List<Produit> aListe)
        {
            foreach (Produit p in mProduitListe)
            {
                if ( ( p.DateAchat.Year == aAnnnee ) || (p.DateVente.Year == aAnnnee) )
                    aListe.Add(p);
            }

            return true;
        }

        internal bool Exists(String value)
        {
            for (int i = 0; i < mProduitListe.Count; i++)
            {
                if (mProduitListe[i].Reference == value)
                    return true;
            }

            return false;
        }

        internal void Clear()
        {
            if (mProduitListe == null)
                mProduitListe = new List<Produit>();
            else
                mProduitListe.Clear();
        }

        internal void SupprimerFrais(int aRef)
        {
            CaisseElement toRemove=null;
            foreach (CaisseElement ce in Frais)
            {
                if (ce.Reference == aRef)
                    toRemove = ce;
            }

            if (toRemove != null)
            {
                mFrais.Remove(toRemove);
                SendChange();
            }
        }

        internal void AjouterRecette(CaisseElement caisseElement)
        {
            mCaisse.Recettes.Add(caisseElement);
            SendChange();
        }

        internal void AjouterDepense(CaisseElement caisseElement)
        {
            mCaisse.Depences.Add(caisseElement);
            SendChange();
        }

        internal bool SupprimerRecette(int aRef)
        {
            CaisseElement toRemove = null;
            foreach (CaisseElement ce in mCaisse.Recettes)
            {
                if (ce.Reference == aRef)
                    toRemove = ce;
            }

            if (toRemove != null)
            {
                mCaisse.Recettes.Remove(toRemove);
                SendChange();

                return true;
            }

            return false;
        }

        internal bool SupprimerDepense(int aRef)
        {
            CaisseElement toRemove = null;
            foreach (CaisseElement ce in mCaisse.Depences)
            {
                if (ce.Reference == aRef)
                    toRemove = ce;
            }

            if (toRemove != null)
            {
                mCaisse.Depences.Remove(toRemove);
                SendChange();

                return true;
            }

            return false;
        }

        internal void SupprimerCaisse(int reference)
        {
            if (SupprimerRecette(reference) == true)
                return;

            SupprimerDepense(reference);
        }

        internal bool SupprimerAchat(ref Produit prod)
        {
            if (prod.DateVente != DateTime.MinValue)
                return false;

            mProduitListe.Remove(prod);
            SendChange();

            return true;
        }

        internal IEnumerable<Produit> GetNonVendus(int aAnnee)
        {
            List<Produit> liste = new List<Produit>();
            foreach (Produit p in mProduitListe)
            {
                if ((p.DateVente == DateTime.MinValue)||(p.DateVente.Year>aAnnee))
                    liste.Add(p);
            }
            return liste; 
        }

        internal bool CheckAchats()
        {
            foreach (Produit p in mProduitListe)
            {
                if (p.DateAchat.Year != mAnnee)
                    return false;
            }

            return true;
        }

        internal bool CheckVentes()
        {
            foreach (Produit p in mProduitListe)
            {
                if ( (p.DateVente != DateTime.MinValue)
                    && (p.DateVente.Year < mAnnee) && (p.DateVente < p.DateAchat))
                    return false;
            }

            return true;
        }

        internal bool CheckFrais()
        {
            foreach (CaisseElement elmt in mFrais)
            {
                if (elmt.Date.Year != mAnnee)
                    return false;
            }

            return true;
        }

        internal bool CheckCaisse()
        {
            foreach (CaisseElement elmt in mCaisse.Recettes)
            {
                if (elmt.Date.Year != mAnnee)
                    return false;
            }

            foreach (CaisseElement elmt in mCaisse.Depences)
            {
                if (elmt.Date.Year != mAnnee)
                    return false;
            }

            return true;
        }

        internal List<String> ErreursAchats()
        {
            List<String> res = new List<string>();
            foreach (Produit p in mProduitListe)
            {
                if (p.DateAchat.Year != mAnnee)
                    res.Add(p.Reference + " " + p.Nom + "       " + p.DateAchat.ToShortDateString());
            }

            return res;
        }

        internal List<String> ErreursVentes()
        {
            List<String> res = new List<string>();
            foreach (Produit p in mProduitListe)
            {
                if ( (p.DateVente != DateTime.MinValue)
                    && (p.DateVente.Year < mAnnee) && (p.DateVente < p.DateAchat))
                    res.Add(p.Reference + " " + p.Nom + "       " + p.DateAchat.ToShortDateString() + "       " + p.DateVente.ToShortDateString());
            }

            return res;
        }

        internal List<String> ErreursCaisses()
        {
            List<String> res = new List<string>();
            foreach (CaisseElement elmt in mCaisse.Recettes)
            {
                if (elmt.Date.Year != mAnnee)
                    res.Add(elmt.Date + " " + elmt.Description + " " + elmt.Somme);
            }

            foreach (CaisseElement elmt in mCaisse.Depences)
            {
                if (elmt.Date.Year != mAnnee)
                    res.Add(elmt.Date + " " + elmt.Description + " " + elmt.Somme);
            }

            return res;
        }

        internal List<String> ErreursFrais()
        {
            List<String> res = new List<String>();
            foreach (CaisseElement elmt in mFrais)
            {
                if (elmt.Date.Year != mAnnee)
                    res.Add(elmt.Date + " " + elmt.Description + " " + elmt.Somme);
            }

            return res;
        }
    }
}
